package demo1;
/**
 * Created with IntelliJ IDEA.
 * Description:
 * User: 石方旭
 * Date: 2022-08-02
 * Time: 13:50
 */

//实现一个阻塞队列
public class MyBlockingQueue {
    private int[] elem;//将元素放到一个数组里面
    private volatile int usedSize;//数组有效个数--也用来判断队列空还是满
    private int front;//对头
    private int rear;//队尾
    //构造方法--初始化
    public MyBlockingQueue(){
        this.elem = new int[1000];//数组初始化1000个元素
        this.usedSize =0;//数组有效个数初始化
        this.front =0;//初始对头下标为0
        this.rear = 0;//初始队尾下标为0
    }

    //实现put方法
    public void put(int val) throws InterruptedException {
        //这里加锁是为了有修改操作,可能有的线程在读有的在写,并且wait要在synchronized中使用
        synchronized(this) {
            //判断队列是否为满,如果满需要等待.
            //为了避免阻塞时间过长,要再次进行判断--使用while
            while (this.usedSize == this.elem.length) {
                this.wait();
            }
            //添加元素将val放在rear位置上,rear往后走
            this.elem[rear] = val;
            rear++;
            //如果rear走到末尾位置,就要从到开始,避免浪费空间
            if(this.rear==this.elem.length){
                this.rear= 0;
            }
            this.usedSize++;//添加元素成功有效个数+1
            this.notify();//用来通知已经添加了一个元素--队列不为空
        }
    }

    //实现take方法--删除对头元素并返回
    public Integer take() throws InterruptedException {
        int ret =0;
        synchronized(this){
            //用来判断队列是否为空,如果为空就要进行等待;
            //等待队列添加元素,在通知--呼应put方法的通知notify
            while(this.usedSize==0){
                this.wait();
            }
            //存放对头元素,front往后走相当于将对头元素删除
            ret = this.elem[front];
            this.front++;
            //front走到队尾越界就从头开始--避免队列浪费空间
            if(front==this.elem.length){
                this.front = 0;
            }
            this.usedSize--;
            this.notify();//删除对头元素来通知队列不满了可以添加元素--呼应put判断是否满
        }
        return ret;//将对头元素返回去
    }

    //测试 生产者-消费者模型
    public static void main(String[] args) {
        MyBlockingQueue queue = new MyBlockingQueue();
        //生产者
        Thread producer = new Thread(()->{
            int n =0;
            while(true){
                try {
                    queue.put(n);
                    System.out.println("生产了 " + n);
                    n++;
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
        producer.start();

        //消费者
        Thread customer = new Thread(()->{
            while(true){
                try {
                    int x = queue.take();
                    System.out.println("消费了"+x);
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
        customer.start();


    }

}
